/****************************************************************************

	COPYRIGHT(C) MAXSI SOFTWARE, JONAS 'SORTIE' TERMANSEN 2008, 2009, 2010

    This file is part of Maxsi Engine.

    Maxsi Engine is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Maxsi Engine is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Maxsi Engine.  If not, see <http://www.gnu.org/licenses/>.

	*/ #include "MaxsiEngineContributors.h" /*

	If you modify this file, please enter your name below and provide contact
	information in MaxsiEngineContributors.h. For more information please see
	MaxsiEngineContributors.h.
	
	Contributors to this file:

	- Jonas 'Sortie' Termansen
	- [your name here]

	MaxsiEngine.dll
	A linkable version of Maxsi Engine

	MaxsiNetworking.cpp
	Multithreaded Networking

****************************************************************************/

#include "MaxsiEngine.h"
#include "winsock2.h"

#define DATA_BUFSIZE 4096
#define REQ_WINSOCK_VER	2

//#define Progress(Value) if ( ProgressFunc) { ProgressFunc(Value); }
#define Progress(Parser)	if (ProgressFunc) { Parser = ProgressFunc(Parser); }

namespace MaxsiEngine
{
//LRESULT APIENTRY Networking_WindowProc(
//    HWND hWnd, 
//    UINT message, 
//    WPARAM wParam, 
//    LPARAM lParam)
//{ 
//	SOCKET	Sock	=	0;
//	int		Error	=	0;
//	int		Event	=	0;
//	
//	switch (message) 
//    {
//        case WM_COMMAND:
//			return 0;
//			break;
//		case WM_SIZE:
//			return 0;
//			break;
//		case WM_PAINT:
//			return 0;
//			break;
//		case WM_DESTROY:
//			WSACleanup();
//			return 0;
//			break;
//		case MSG_NETWORK_EVENT:
//			Sock	=	(SOCKET)wParam;
//			Error	=	HIWORD(lParam);
//			Event	=	LOWORD(lParam);
//
//
//
//
//			return 0;
//			break;
//		default:
//			return (DefWindowProc(hWnd, message, wParam, lParam));
//			break;
//    }
//    return (0);
//}
//
//bool	Networking_WindowRegister(HINSTANCE hInstance)
//{
//	WNDCLASS  wc = {0};
//
//    wc.lpfnWndProc = (WNDPROC) Networking_WindowProc;
//    wc.hInstance = (HINSTANCE)hInstance;
//    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
//    wc.lpszClassName = TEXT("Networking_Window");
//
//    return (RegisterClass(&wc)>0);
//}
//
//HWND	Networking_WindowCreate(HINSTANCE hInstance)
//{
//    return CreateWindow(
//        TEXT("Networking_Window"),
//        TEXT("Networking_Window"),
//        0,
//        CW_USEDEFAULT, 0,
//        0, 0,
//        NULL, NULL, hInstance, NULL );
//}

LINK	HTTPParser_Struct	ConnectAndSendHTTPQuery(char* Buffer, size_t BufferLen, char* HostName, NetworkingProgress_Type ProgressFunc)
{
	u_short		Port	=	80;

	HTTPParser_Struct Parser;
	memset(&Parser,0,sizeof(Parser));

	Progress(Parser);

    WSADATA wsaData;
	//char* Result = 0;

    if (WSAStartup(MAKEWORD(REQ_WINSOCK_VER,0), &wsaData)==0)
    {
        // Check if major version is at least REQ_WINSOCK_VER
        if (LOBYTE(wsaData.wVersion) >= REQ_WINSOCK_VER)
        {
			SOCKET Sock;
			sockaddr_in SockAddr;

			SockAddr.sin_family = AF_INET;
			SockAddr.sin_port = htons((u_short)Port);
			SockAddr.sin_addr.S_un.S_addr = HostToIp(HostName);

			if ((Sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != INVALID_SOCKET)
			{
				int	Connect_ResponseCode	= connect(Sock, reinterpret_cast<sockaddr*>(&SockAddr), sizeof(SockAddr));
				if (Connect_ResponseCode==0)
				{
					int ASyncSelect_ResponseCode = 0;//WSAAsyncSelect(Sock,Networking_Window,MSG_NETWORK_EVENT,FD_READ | FD_WRITE | FD_CLOSE);
					if (ASyncSelect_ResponseCode==0)
					{
						// Great!
						int BytesSent = send(Sock,Buffer,(int)BufferLen,0);
						if ( BytesSent == SOCKET_ERROR)
						{
#ifdef _DEBUG
							int	ErrorCode =	WSAGetLastError();
							int leet = 1337;
#endif

							// Damn.
						}
						else
						{
							//List	DataList = CreateList(1);
							//size_t	FragmentNumber = 0;
							int		DataRecieved = 0;
							int		DataRecievedTotal = 0;	
							char	Buffer[65536];
							do {
								DataRecieved = recv(Sock,Buffer,65536,0);

								if ( DataRecieved == SOCKET_ERROR )
								{
									Parser.ShouldDisconnect		=	true;
									int		Error	=	WSAGetLastError();
									char	ErrorSTR[33];

									_itoa_s(Error,ErrorSTR,33,10);

									char*	Msg		=	BuildString(3,"Winsock Error: ",ErrorSTR, " happened in MaxsiEngine::ConnectAndSendHTTPQuery(...).\r\n\r\nFor the exact error codes please see http://msdn.microsoft.com/en-us/library/ms740668(VS.85).aspx\r\n" SupportId(41));

									//MessageBoxA(NULL,Msg,"Maxsi Engine Error",MB_ICONERROR);
									
									delete[] Msg;
								}
								else
								{
									DataRecievedTotal+=DataRecieved;
									//if ( DataRecieved > 0)
									//{
									//	FragmentNumber++;
									//	SetListSize(DataList,FragmentNumber);
									//	SetListEntry(DataList,(unsigned int)FragmentNumber-1,Buffer,DataRecieved);
									//}

									// Progress!
									//NetworkingStruct.PureBuffer = BufferListToBuffer(DataList);
									//NetworkingStruct.ParsedBuffer_Len = (size_t)DataRecieved;
									//NetworkingStruct.ParsedBuffer = ParseHTTPResponse(NetworkingStruct.PureBuffer, NetworkingStruct.PureBuffer_Len, &NetworkingStruct.ParsedBuffer_Len, ProgressFunc);

									Parser.Add = Buffer;
									Parser.AddLenght = (size_t)DataRecieved;
									
									Parser = ParseHTTPResponse(Parser);
									
									Progress(Parser)

									Parser.Add = 0;

									//delete[] NetworkingStruct.ParsedBuffer;
									//delete[] NetworkingStruct.PureBuffer_Len;
								}
							} while ( DataRecieved > 0 && !Parser.ShouldDisconnect);

							if ( DataRecieved == -1 )
							{
#ifdef _DEBUG
								// Failure.
								int	ErrorCode =	WSAGetLastError();
								int leet = 1337;
#endif
							}
							else
							{
								//char* TotalBuffer = new char[DataRecievedTotal+1];
								//size_t Offset = 0;
								//for (size_t N = 0; N < FragmentNumber; N++)
								//{
								//	char*	Data		=	(char*)	GetListEntry	(DataList,(unsigned int)N);
								//	size_t	Data_Size	=			GetListEntrySize(DataList,(unsigned int)N);
								//	memcpy(TotalBuffer+Offset,Data,Data_Size);
								//	Offset+=Data_Size;
								//}
								//DeleteList(DataList);
								//TotalBuffer[Offset] = 0;
								//memcpy(ResponseSize,&DataRecievedTotal,sizeof(size_t));
								//Result = ParseHTTPResponse(TotalBuffer,(size_t)DataRecievedResponseSize, ProgressFunc);
								//delete[] TotalBuffer;
								//Result = Parser.Out;
							}							
						}
					}
					else
					{
						// Failure.
#ifdef _DEBUG
						int	ErrorCode =	WSAGetLastError();
#endif
					}
				}
				else
				{
#ifdef _DEBUG
					int	ErrorCode =	WSAGetLastError();
#endif
				}
				
				closesocket(Sock);
			}
		}
    }
	
	/*if (!Success) { DestroyWindow(Networking_Window); Networking_Window = NULL; }*/

    return Parser;
}

#if 0
// TODO: VALIDATE THE BUFFER ACTUALLY IS A VALID HTTP STREAM AND BE HTTP COMPLIANT!
LINK	char*	ParseHTTPResponse(char* Buffer, size_t BufferLen, size_t* ResponseSize, NetworkingProgress_Type ProgressFunc)
{
	char*	NL						=	"\r\n";
	size_t	NLL						=	strlen(NL);
	char*	ReadP					=	0;
	size_t	Read					=	0;
	size_t	ReadTMP					=	0;
	size_t	StatusLineLen			=	FindString(Buffer,NL);
	char*	StatusLine				=	new char[StatusLineLen+1];
	char*	Result					=	0;

	memcpy(StatusLine,Buffer,StatusLineLen);
	StatusLine[StatusLineLen]		= 0;

	size_t	HTTPVersionLen			=	FindString(StatusLine," ");
	char*	HTTPVersion				=	new char[HTTPVersionLen+1];
	memcpy(HTTPVersion,StatusLine,HTTPVersionLen);
	HTTPVersion[HTTPVersionLen]		= 0;

	// No support for anything but HTTP/1.1!
	if (_strcmpi(HTTPVersion,"http/1.1")==0)
	{
		size_t	StatusCodeLen			=	FindString(StatusLine+HTTPVersionLen+1," ");
		char*	StatusCodeStr			=	new char[StatusCodeLen+1];
		memcpy(StatusCodeStr,StatusLine+HTTPVersionLen+1,StatusCodeLen);
		StatusCodeStr[StatusCodeLen]	=	0;

		int		StatusCode				=	atoi(StatusCodeStr);

		// Was the status code somewhat usable?
		if (StatusCode)
		{
			// Proceed to the header fields.
			Read += StatusLineLen + NLL;

			// First count the amount of header fields.
			ReadTMP = Read;
			size_t	HeaderLineLen	=	0;
			size_t	NumHeaders		=	0;
			
			do
			{	
				ReadP			= Buffer+ReadTMP;
				HeaderLineLen	= FindString(Buffer+ReadTMP,NL);
				if (HeaderLineLen == 0)
				{
					break;	// An empty line marks the end of the head.
				}
				else
				{
					NumHeaders++;
					ReadTMP+=HeaderLineLen+NLL;
					// Don't exceed the buffersize. TODO: Ensure this works.
					if ( ReadTMP > BufferLen )
					{
						break;
					}
				}
			}
			while (true);

			bool	Chunked	=	false;

			List	Headers		=	CreateList(NumHeaders);
			for (size_t	N = 0; N < NumHeaders; N++)
			{
				HeaderLineLen	= FindString(Buffer+Read,NL);
				char* HeaderLine = new char[HeaderLineLen+1];
				memcpy(HeaderLine,Buffer+Read,HeaderLineLen);
				HeaderLine[HeaderLineLen] = 0;
				if (_stricmp(HeaderLine,"Transfer-Encoding: chunked")==0)
				{
					Chunked = true;
				}
				SetListEntry(Headers,(unsigned int)N,HeaderLine,HeaderLineLen);
				delete[] HeaderLine;
				Read+=HeaderLineLen+NLL;
			}
			Read+=NLL;

			if ( Chunked ) // Transfer-Encoding: chunked
			{
				// The headers are now parsed. Read the data as if the transfer-coding was chunked
				// TODO: Ensure the transfer coding, actually, is chunked!

				/*     Chunked-Body   = *chunk
										last-chunk
										trailer
										CRLF
					   chunk          = chunk-size [ chunk-extension ] CRLF
										chunk-data CRLF
					   chunk-size     = 1*HEX
					   last-chunk     = 1*("0") [ chunk-extension ] CRLF
					   chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
					   chunk-ext-name = token
					   chunk-ext-val  = token | quoted-string
					   chunk-data     = chunk-size(OCTET)
					   trailer        = *(entity-header CRLF)
				*/

				
				size_t	ChunkLineLen	=	0;
				char*	ChunkLine		=	0;
				size_t	ChunkSize		=	0;
				size_t	ChunkSizeTotal	=	0;
				List	Chunks			=	CreateList(0);
				size_t	ChunkNum		=	0;
				size_t	ChunkEx			=	0;

				while (true)
				{
					ChunkLineLen	=	FindString(Buffer+Read,NL);
					ChunkLine		=	new char[ChunkLineLen+1];
					memcpy(ChunkLine,Buffer+Read,ChunkLineLen);
					ChunkLine[ChunkLineLen]	=	0;
					Read+=ChunkLineLen+NLL;
/*
HTTP/1.1 200 OK
Date: Sat, 13 Sep 2008 14:28:20 GMT
Server: Apache
X-Powered-By: PHP/5.2.6
Set-Cookie: sessionid=4d4d304e316b3b6f9802366dd4d15240; path=/; domain=.maxsi.dk
Connection: close
Transfer-Encoding: chunked
Content-Type: text/plain

29 
Error "The product is already installed."
0
*/


					// Detect any chunk-extensions
					
					ChunkEx			=	FindString(ChunkLine,";");

					if (ChunkEx == 0)
					{
						ChunkSize = HEXTOI(ChunkLine);
						ChunkSizeTotal+=ChunkSize;
						if ( ChunkSize)
						{
							ChunkNum++;
							SetListSize(Chunks,ChunkNum);
							SetListEntry(Chunks,(unsigned int)ChunkNum-1,Buffer+Read,ChunkSize);
							Read+=ChunkSize+NLL;
						}
						else
						{
							break;
						}
					}
					else
					{
						// Not supported.
					}

					delete[] ChunkLine;
				};

				char* TotalBuffer = new char[ChunkSizeTotal+1];
				size_t Offset = 0;
				for (size_t N = 0; N < ChunkNum; N++)
				{
					char*	Data		=	(char*)	GetListEntry	(Chunks,(unsigned int)N);
					size_t	Data_Size	=			GetListEntrySize(Chunks,(unsigned int)N);
					memcpy(TotalBuffer+Offset,Data,Data_Size);
					Offset+=Data_Size;
				}	
				memcpy(ResponseSize,&ChunkSizeTotal,sizeof(size_t));
				DeleteList(Chunks);
				TotalBuffer[Offset] = 0;
				Result = TotalBuffer;
			}
			else	// Transfer-Encoding != chunked
			{
				size_t TotalBufferSize = BufferLen-Read;
				char* TotalBuffer = new char[TotalBufferSize+1];
				memcpy(TotalBuffer,Buffer+Read,TotalBufferSize);
				TotalBuffer[TotalBufferSize] = 0;
				memcpy(ResponseSize,&TotalBufferSize,sizeof(size_t));
				Result = TotalBuffer;
			}
		}

		delete[]	StatusCodeStr;
	}

	delete[] HTTPVersion;
	delete[] StatusLine;

	return Result;


}
#endif

// Deletes all the data stored in the HTTPParser_Struct 
LINK	bool				DeleteHTTPParser_Struct(HTTPParser_Struct Parser)
{
	if (Parser.Add)		delete[] Parser.Add;
	if (Parser.In)		delete[] Parser.In;
	if (Parser.Out)		delete[] Parser.Out;
	if (Parser.Headers)	DeleteList(Parser.Headers);
	return true;
}

// Rewritten
LINK	HTTPParser_Struct	ParseHTTPResponse(HTTPParser_Struct Parser)
{
	char*	NL						=	"\r\n";
	size_t	NLL						=	strlen(NL);

	// Add the new fragment to the read buffer

	if ( Parser.Add )
	{
		char*	TMP	= new char[Parser.InLenght+Parser.AddLenght];
		memcpy	(TMP,Parser.In,Parser.InLenght);
		memcpy	(TMP+Parser.InLenght,Parser.Add,Parser.AddLenght);

		delete[] Parser.In;
		Parser.In = TMP;
		Parser.InLenght+=Parser.AddLenght;
	}

	// Step 0: Goto Step 1	
	if ( Parser.Step == 0 ) { Parser.Step++; }

	// Step 1: Read the response header!
	if ( Parser.Step == 1 )
	{
		size_t FirstLineBreak = FindStringEx(Parser.In,Parser.InLenght,NL,NLL);

		if (FirstLineBreak == ULONG_MAX)
		{
			// The first line is not recieved yet. Wait for the next call
			//Parser.Step = -1;
			//Parser.ResponseCode = -1;
		}
		else
		{
			char* HeaderLine = new char[FirstLineBreak+1];
			Parser.Read = FirstLineBreak+NLL;
			memcpy(HeaderLine,Parser.In,FirstLineBreak);
			HeaderLine[FirstLineBreak] = 0;
			AUTODELETEAR HeaderLine_Deleter(HeaderLine);


			size_t	HTTPVersionLen			=	FindString(HeaderLine," ");
			char*	HTTPVersion				=	new char[HTTPVersionLen+1];
			AUTODELETEAR HTTPVersion_Deleter(HTTPVersion);

			memcpy(HTTPVersion,HeaderLine,HTTPVersionLen);

			HTTPVersion[HTTPVersionLen]		=	0;
			
			// No support for anything but HTTP/1.1!
			if (_strcmpi(HTTPVersion,"http/1.1")!=0)
			{
				Parser.Step = -1;
				Parser.ResponseCode = -2;
			}
			else
			{
				size_t	StatusCodeLen			=	FindString(HeaderLine+HTTPVersionLen+1," ");
				char*	StatusCodeStr			=	new char[StatusCodeLen+1];

				memcpy(StatusCodeStr,HeaderLine+HTTPVersionLen+1,StatusCodeLen);

				StatusCodeStr[StatusCodeLen]	=	0;

				Parser.ResponseCode				=	atoi(StatusCodeStr);

				Parser.Step++;

				delete[] StatusCodeStr;
			}
		}
	}

	// Step 2: Parse the HTTP headers
	if ( Parser.Step == 2 )
	{
		// Ensure we have got an array
		if (!Parser.Headers)
		{
			Parser.Headers = CreateList(0);
		}

		// Loop until an empty line is found		
		while (true)
		{
			size_t LineBreak = FindStringEx(Parser.In+Parser.Read,Parser.InLenght-Parser.Read,NL,NLL);

			// See if we have recieved the next line break yet
			
			if (LineBreak == ULONG_MAX)
			{
				// Nope. Continue next time
				break;
			}
			else if (LineBreak == 0)
			{
				// Empty line. End of HTTP headers
				Parser.Step++;
				Parser.Read+=NLL;
				break;
			}
			else
			{
				size_t	Line_Len		=	LineBreak;
				char*	Line			=	new char[Line_Len+1];
						Line[Line_Len]	=	0;	

						memcpy(Line,Parser.In+Parser.Read,Line_Len);

				SetListSize(Parser.Headers,GetListSize(Parser.Headers)+1);
				SetListEntry(Parser.Headers,(unsigned int)GetListSize(Parser.Headers)-1,Line,Line_Len+1);

				delete[] Line;

				// Skip to the next line
				Parser.Read += Line_Len+NLL;
			}
		};
	}

	// Step 3: Read the HTTP data
	if ( Parser.Step == 3 )
	{
/*     Chunked-Body   = *chunk
						last-chunk
						trailer
						CRLF
	   chunk          = chunk-size [ chunk-extension ] CRLF
						chunk-data CRLF
	   chunk-size     = 1*HEX
	   last-chunk     = 1*("0") [ chunk-extension ] CRLF
	   chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
	   chunk-ext-name = token
	   chunk-ext-val  = token | quoted-string
	   chunk-data     = chunk-size(OCTET)
	   trailer        = *(entity-header CRLF)
*/
		// TODO: CHECK FOR CHUNKED OR NOT!
		//TODOFAIL();

		while (true)
		{
			// New chunk
			if (Parser.ChunkBegin == 0)
			{
				// Search for the line break
				size_t LineBreak = FindStringEx(Parser.In+Parser.Read,Parser.InLenght-Parser.Read,NL,NLL);
				
				if ( LineBreak == ULONG_MAX )
				{
					// Line break is not recieved yet
					break;
				}
				else
				{
					// Get the chunk line
					size_t	ChunkSize_Len				=	LineBreak;
					char*	ChunkSize					=	new char[LineBreak+1];
							ChunkSize[ChunkSize_Len]	=	0;
					size_t	ChunkEx						=	FindString(ChunkSize,";");

					AUTODELETEAR ChunkSize_Deleter(ChunkSize);

					memcpy(ChunkSize,Parser.In+Parser.Read,ChunkSize_Len);
					Parser.Read+=ChunkSize_Len+NLL;

					if (ChunkEx==ULONG_MAX)
					{
						Parser.ChunkLenght = HEXTOI(ChunkSize);
						if (Parser.ChunkLenght == 0)
						{
							// Last chunk!
							Parser.ShouldDisconnect = true;
							// Just disconnect!
							break;
						}
						Parser.ChunkBegin = Parser.Read;
					}
					else
					{
						// Chunk Extensions are not supported yet
						Parser.Step = -1;
						Parser.ResponseCode = -3;
						break;
					}
				}
			}

			// Read the chunk if available
			if (Parser.ChunkBegin > 0 && Parser.ChunkBegin != ULONG_MAX)
			{
				size_t ChunkAvailable = Parser.InLenght-Parser.Read;
				size_t ChunkLeft = Parser.ChunkLenght-(Parser.Read-Parser.ChunkBegin);
				if (ChunkAvailable >= ChunkLeft)
				{
					// The rest of the chunk (and perhaps more) is available
					// Copy the pure data into the output buffer!
					char* TMP = new char[Parser.OutLenght+ChunkLeft];
					memcpy(TMP,Parser.Out,Parser.OutLenght);
					memcpy(TMP+Parser.OutLenght,Parser.In+Parser.Read,ChunkLeft);
					Parser.OutLenght+=ChunkLeft;
					delete[] Parser.Out;
					Parser.Out = TMP;

					// chunk-data CRLF
					// We can't rely on the fact that the client should have recieved a CRLF,
					// so just assume we didn't check check it next time. (See below);
					Parser.ChunkBegin = ULONG_MAX;


					Parser.Read += ChunkLeft;// + NLL; // We CANNOT rely on this, (adding the NLL)
					// if we do, then we might have a possible situation
					// where, Parser.InLenght < Parser.Read,
					// which means Parser.InLenght - Parser.Read < 0,
					// and since it is a size_t, then 4294967296 > Parser.InLenght - Parser.Read
					// and since Parser.Read is a small'ish number compared to 4294967296,
					// then the program will read a huge amount of data in FindStringEx
					// usually beyond what is possible for us --> Crash!!

					//Parser.ChunkBegin = 0;
					Parser.ChunkLenght = 0;
				}
				else
				{
					// Only a fragment of the chunk is available right now
					// Copy whatever we got into the output buffer!
					char* TMP = new char[Parser.OutLenght+ChunkAvailable];
					memcpy(TMP,Parser.Out,Parser.OutLenght);
					memcpy(TMP+Parser.OutLenght,Parser.In+Parser.Read,ChunkAvailable);
					Parser.OutLenght+=ChunkAvailable;
					delete[] Parser.Out;
					Parser.Out = TMP;

					Parser.Read += ChunkAvailable;

					// Stop parsing data and wait for more to arrive
					break;
				}
				
				if (Parser.ChunkBegin == ULONG_MAX)
				{
					Parser.ChunkBegin	=	0;					
					// Protocol specifies that a CRLF should come here
					// Don't check it, though, just skip two characters ahead when possible.
					// If it isn't a CRLF, then the server is breaking the protocol, and any faults should be
					// detected later on.

					if ( Parser.InLenght-Parser.Read >= NLL)
					{
						Parser.Read+=NLL;
					}
					else
					{
						// Some router or something turned in the pack before the CRLF is recieved,
						// which is unusual, but could happen. Just wait for the CRLF to arrive.
						break;
					}
				}
			}
		};
	}

	// Return the struct containing the data!
	return Parser;
}

LINK	IP		HostToIp(const char* Host)
{
    HOSTENT *pHostent;

    // Get hostent structure for hostname:
    if (!(pHostent = gethostbyname(Host)))
	{
		return inet_addr(Host);
	}

    // Extract primary IP address from hostent structure:
    if (pHostent->h_addr_list && pHostent->h_addr_list[0])
        return *reinterpret_cast<IP*>(pHostent->h_addr_list[0]);

    return 0;
}



LINK	int	SendHTTPQuery(HWND Networking_Window, char* Buffer, size_t BufferLen, SOCKET Sock, ProgressFunc_Type ProgressFunc)
{
	return WSAAsyncSelect(Sock,Networking_Window,MSG_NETWORK_EVENT,FD_READ | FD_WRITE | FD_CLOSE);

	// TODO
	return 0;
}

LINK	BOOL	HTTPParse_ShouldClose(char* Buffer, int BufferSize)
{
	return FALSE;
}

// TODO MAKE THIS PROPER AND WORK FOR ALL URI'S!
LINK	char*	GetHostFromURI(char* URI)
{
	size_t Len = FindString(URI,"/");
	if ( Len == ULONG_MAX ) { Len = 0; }
	char* Result = new char[Len+1];
	memcpy(Result,URI,Len);
	Result[Len] = 0;
	return Result;
}
// TODO MAKE THIS PROPER AND WORK FOR ALL URI'S!
LINK	char*	GetResourceFromURI(char* URI)
{
	size_t Len = FindString(URI,"/");
	if ( Len == ULONG_MAX ) { Len = 0; }
	char* Result = new char[strlen(URI)-Len+1];
	memcpy(Result,URI+Len,strlen(URI)-Len);
	Result[strlen(URI)-Len] = 0;
	return Result;
}

LINK	HTTPParser_Struct	UploadFile(char* Host, char* Resource, char* FileName, char* Buffer, size_t BufferLen, NetworkingProgress_Type ProgressFunc )
{
	FileName = BuildString(1,FileName);
	str_replace(FileName," ","+");
	Resource = BuildString(1,Resource);
	str_replace(Resource," ","+");
/*
POST http://www.maxsi.dk/framework/action.php?action=recieve HTTP/1.1
Host: www.maxsi.dk
Content-type: multipart/form-data; boundary=AaB03x
Content-Length: 800

--AaB03x
Content-Disposition: file; name="file"; filename="TEST_FILE_LOL.txt" 
Content-Type: text/plain 

LOL DOES THIS WORK
OSHI
--AaB03x
*/

	//size_t Request_Len = 0;
	size_t RequestBodyBodyLen = 0;
	char* RequestBodyHeader = BuildString(3,"--AaB03x\r\nContent-Disposition: file; name=\"file\"; filename=\"",FileName,"\"\r\nContent-Type: application/octet-stream\r\n\r\n");
	char* RequestBodyBody = new char[strlen(RequestBodyHeader)+BufferLen+strlen("\r\n--AaB03x\r\n")];
	memcpy(RequestBodyBody,RequestBodyHeader,strlen(RequestBodyHeader));
	memcpy(RequestBodyBody+strlen(RequestBodyHeader),Buffer,BufferLen);
	memcpy(RequestBodyBody+strlen(RequestBodyHeader)+BufferLen,"\r\n--AaB03x\r\n",strlen("\r\n--AaB03x\r\n"));
	RequestBodyBodyLen = strlen(RequestBodyHeader)+BufferLen+strlen("\r\n--AaB03x\r\n");
	char Content_Lenght[65];
	_ui64toa_s((unsigned int)RequestBodyBodyLen/*-strlen("\r\n--AaB03x\r\n")*/,Content_Lenght,65,10);

	char* RequestHeader = BuildString(7,"POST ",Resource," HTTP/1.1\r\nHost: ",Host,"\r\nConnection: Close\r\nContent-type: multipart/form-data; boundary=AaB03x\r\nContent-Length: ",Content_Lenght,"\r\n\r\n");
	
	char* Request = new char[strlen(RequestHeader)+RequestBodyBodyLen];
	memcpy(Request,RequestHeader,strlen(RequestHeader));
	memcpy(Request+strlen(RequestHeader),RequestBodyBody,RequestBodyBodyLen);
	
	HTTPParser_Struct Reply = ConnectAndSendHTTPQuery(Request,strlen(RequestHeader)+RequestBodyBodyLen,Host,ProgressFunc);

	delete[] Request;
	delete[] RequestHeader;
	delete[] RequestBodyBody;
	delete[] RequestBodyHeader;
	//DeleteHTTPParser_Struct(Reply);
	delete[] FileName;
	delete[] Resource;
	return Reply;
}

}
